#include "poly_partition.h"
#include "polygon2d.h"

using namespace geometry;

// {
//     int failures = 0;
//     TPPLPartition pp;

//     list<TPPLPoly> testpolys, result, expectedResult;

//     ReadPolyList("test_input.txt", &testpolys);
 

//     result.clear();
//     expectedResult.clear();

//     printf("Testing Triangulate_OPT: ");
//     pp.Triangulate_OPT(&(*testpolys.begin()), &result);
//     ReadPolyList("test_triangulate_OPT.txt", &expectedResult);
//     if (ComparePoly(&result, &expectedResult)) {
//         printf("success\n");
//     } else {
//         printf("failed\n");
//         failures++;
//     }
//     DrawPolyList("tri_opt.bmp", &result);

//     result.clear();
//     expectedResult.clear();

//     printf("Testing Triangulate_MONO: ");
//     pp.Triangulate_MONO(&testpolys, &result);
//     ReadPolyList("test_triangulate_MONO.txt", &expectedResult);
//     if (ComparePoly(&result, &expectedResult)) {
//         printf("success\n");
//     } else {
//         printf("failed\n");
//         failures++;
//     }
//     DrawPolyList("tri_mono.bmp", &result);

//     result.clear();
//     expectedResult.clear();

//     printf("Testing ConvexPartition_HM: ");
//     pp.ConvexPartition_HM(&testpolys, &result);
//     ReadPolyList("test_convexpartition_HM.txt", &expectedResult);
//     if (ComparePoly(&result, &expectedResult)) {
//         printf("success\n");
//     } else {
//         printf("failed\n");
//         failures++;
//     }
//     DrawPolyList("conv_hm.bmp", &result);

//     result.clear();
//     expectedResult.clear();

//     printf("Testing ConvexPartition_OPT: ");
//     pp.ConvexPartition_OPT(&(*testpolys.begin()), &result);
//     ReadPolyList("test_convexpartition_OPT.txt", &expectedResult);
//     if (ComparePoly(&result, &expectedResult)) {
//         printf("success\n");
//     } else {
//         printf("failed\n");
//         failures++;
//     }
//     DrawPolyList("conv_opt.bmp", &result);

//     return failures;
// }
class OutPolyPartition
{
public:
    enum Option : uint8_t { TRIANGLE_OPT = 0,
                            TRIANGLE_MONO,
                            CONVEX_OPT,
                            CONVEX_HM };
    // 多边形凸分解或者三角分解
    static void GetPartition(const Polygon2d &in_poly, OutPolyPartition::Option option, std::vector<Polygon2d> &out_poly)
    {
        //
        TPPLPartition pp;
        std::list<TPPLPoly> testpolys, result;
        {
            TPPLPoly pp_in;
            pp_in.Init(in_poly.num_points());
            pp_in.SetHole(false);
            int index = 0;
            for (auto &item : in_poly.points()) {
                pp_in[index].x = item.x();
                pp_in[index].y = item.y();
                index ++;
            }
            int num_points = pp_in.GetNumPoints();
            printf("num_points:%d\n", num_points);
            //
            testpolys.push_back(pp_in);
        }
        //
        int res;
        if (option == TRIANGLE_OPT) {
            printf("Testing Triangulate_OPT \n");
            res = pp.Triangulate_OPT(&(*testpolys.begin()), &result);
        }
        if (option == TRIANGLE_MONO) {
            printf("Testing Triangulate_MONO: ");
            res = pp.Triangulate_MONO(&testpolys, &result);
        }
        if (option == CONVEX_OPT) {
            printf("Testing ConvexPartition_OPT: ");
            res = pp.ConvexPartition_OPT(&(*testpolys.begin()), &result);
        }
        if (option == CONVEX_HM) {
            printf("Testing ConvexPartition_HM: \n");
            res = pp.ConvexPartition_HM(&testpolys, &result);
        }

        printf("res:%d\n", res);
        {
            for (auto &item : result) {
                printf("get one partion triangle\n ");
                int count = item.GetNumPoints();
                std::vector<Vec2d> pp_out;
                for (int i = 0; i < count; i++) {
                    pp_out.push_back(Vec2d(item[i].x,item[i].y)); 
                }
                out_poly.push_back(Polygon2d(pp_out));
            }
        }
        // end;
    }
    // 读取测试文件，存储了多边形样例
    static void ReadPoly(FILE *fp, TPPLPoly *poly)
    {
        int i, numpoints, hole;
        float x, y;

        fscanf(fp, "%d\n", &numpoints);
        poly->Init(numpoints);

        fscanf(fp, "%d\n", &hole);
        if (hole) {
            poly->SetHole(true);
        }

        for (i = 0; i < numpoints; i++) {
            fscanf(fp, "%g %g\n", &x, &y);
            (*poly)[i].x = x;
            (*poly)[i].y = y;
        } 
    }

    static void ReadPoly(const char *filename, TPPLPoly *poly)
    {
        FILE *fp = fopen(filename, "r");
        if (!fp) {
            printf("Error reading file %s\n", filename);
            return;
        }
        ReadPoly(fp, poly);
        fclose(fp);
    }
    static void ReadPolyList(FILE *fp, list<TPPLPoly> *polys)
    {
        int i, numpolys;
        TPPLPoly poly;

        polys->clear();
        fscanf(fp, "%d\n", &numpolys);
        for (i = 0; i < numpolys; i++) {
            ReadPoly(fp, &poly);
            polys->push_back(poly);
        }
    }
    static void ReadPolyList(const char *filename, list<TPPLPoly> *polys)
    {
        FILE *fp = fopen(filename, "r");
        if (!fp) {
            printf("Error reading file %s\n", filename);
            return;
        }
        ReadPolyList(fp, polys);
        fclose(fp);
    }
    // 从文本文件读取示例并转换为Polygon2d
    static void  LoadDefaultTestInputToPolygon2d(Polygon2d &polygon_read) {
        //
        const char *file_name = "test_poly_partition/test_input.txt";
        list<TPPLPoly> testpolys;
        ReadPolyList(file_name, &testpolys);
        if (testpolys.empty() == true) {
            printf("read test_input error;\n");
            return ;
        }
        //
        {
            list<TPPLPoly> *polys = &testpolys;
            list<TPPLPoly>::iterator iter;
            for (iter = polys->begin(); iter != polys->end(); iter++) {
                // WritePoly(fp, &(*iter));
                TPPLPoly *poly = &(*iter);
                if (poly->IsHole() == false) {
                    int count = poly->GetNumPoints();
                    std::vector<Vec2d> pp_out;
                    for (int i = 0; i < count; i++) {
                        pp_out.push_back(Vec2d((*poly)[i].x, -(*poly)[i].y) * (1.0 / 30) + Vec2d(0, 10));
                    }
                    polygon_read = (Polygon2d(pp_out));
                    //
                    break;
                }
            }
        }
    }
};

